/*
 * Jenny Ruppen 09-730-391
 * Sebastien Goldberg 08-914-855
 * Henry Raymond 08-928-061
 * Stefan Mussato 09-752-270
 */
 
package ch.uzh.ifi.sopra.gruppe9.game;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;


/**
 * Server-side class for the action location "construction authority", where
 * tower elements can be built into towers. Implements IActionLocation.
 */
@SuppressWarnings("serial")
public class ConstructionAuthority extends UnicastRemoteObject implements IRmiActionLocation {

	
	/**
	 * Game board
	 */
	private IGameBoard gameBoard;
	
	
	/**
	 * Array of the slots where buying agent cards can be placed. 
	 * (0 = no card, 1 = one card in the color of the color constraint, 2 = two cards)
	 */
	private int[] buyingAgentSlots;
	
	
	/**
	 * Color constraint for buying agent cards in this shop.
	 */
	private BuyingAgent.Color colorConstraint = BuyingAgent.Color.NONE;
	
	
	/**
	 * Constructor
	 */
	public ConstructionAuthority(IGameBoard gameBoard) throws RemoteException {
		super();
		
		this.gameBoard = gameBoard;
		
		buyingAgentSlots = new int[7];
		
		for(int i = 0; i < buyingAgentSlots.length; i++) {
			buyingAgentSlots[i] = 0;
		}
	}

	
	/**
	 * Returns array of the slots where buying agent cards can be placed. 
	 * (0 = no card, 1 = one card in the color of the color constraint, 2 = two cards)
	 */
	@Override
	public int[] getBuyingAgentSlots() throws RemoteException {
		return buyingAgentSlots;
	}

	
	/**
	 * Returns id of color of color constraint. (see enumToIntTranslator in class BuyingAgent)
	 */
	@Override
	public int getColorConstraint() throws RemoteException {
		return BuyingAgent.enumToInt(colorConstraint);
	}

	
	/**
	 * Builds together towers out of a number (parameter1) of tower elements,
	 * according to instructions (parameter2) for player (playerIndex).
	 * All towers of the player have to be given, not only the new ones.
	 * And all existing towers have to be given in the same order as the last time.
	 * If only one buying agent card is used: buyingAgentID2 = -1 
	 */
	@Override
	public boolean doAction(int playerIndex, int buyingAgentID1, int buyingAgentID2, int parameter1, String parameter2) throws RemoteException {
		
		IPlayer player = gameBoard.getPlayer(playerIndex);
		
		if(buyingAgentSlots[parameter1] != 0) { // Check if buying agent card slot is free.
			System.err.println("Error: Chosen buying agent slot is not free.");
			return false;
		}
		
		if(gameBoard.getSeason() < 4 || buyingAgentID2 == -1) { // If not in forth season or one buying agent card (change of original rules)
			
			if(colorConstraint != BuyingAgent.Color.NONE) { // Color constraint
				if(new BuyingAgent(buyingAgentID1).getColor() != colorConstraint) {
					System.err.println("Error: Color of buying agent card does not comply with color constraint.");
					return false;
				}
			} else {
				colorConstraint = new BuyingAgent(buyingAgentID1).getColor(); // Set color constraint
			}
			
			if(buyingAgentID2 != -1) { // Two buying agent card
				System.err.println("Error: Cannot give two cards at the construction authority (except in season 4).");
				return false;
			}
			
			if(!player.removeBuyingAgent(buyingAgentID1)) {
				System.err.println("Error: Player doesn't have given buying agent card. (Buying agent ID: " + buyingAgentID1 + ")");
				return false;
			}
			
			// Put one buying agent cards on the chosen slot
			buyingAgentSlots[parameter1] = 1;
		
		} else { // If in forth season and two buying agent cards
			
			if(colorConstraint == BuyingAgent.Color.NONE) { // No Color constraint
				System.err.println("Error: Cannot give two cards when there is no color constraint.");
				return false;
			}
			
			if(!player.removeBuyingAgent(buyingAgentID1)) {
				System.err.println("Error: Player doesn't have first given buying agent card. (Buying agent ID: " + buyingAgentID1 + ")");
				return false;
			}
			
			if(!player.removeBuyingAgent(buyingAgentID2)) {
				System.err.println("Error: Player doesn't have second given buying agent card. (Buying agent ID: " + buyingAgentID2 + ")");
				return false;
			}
			
			// Put two buying agent cards on the chosen slot
			buyingAgentSlots[parameter1] = 2;
			
		}
		
		
		ArrayList<Tower> playerTowers = player.getTowers();
		
		int newElements = 0; // Number of new elements that are being built into the towers
		
		String[] towerInstructions;
		
		if(!parameter2.equals("")) {
			towerInstructions = parameter2.split(";");
		} else {
			towerInstructions = new String[0];
		}
		
		for(int i = 0; i < towerInstructions.length; i++) {
			
			// if new tower
			if(i >= playerTowers.size()) {
				// split tower-building instructions
				String[] towerElements = towerInstructions[i].split(",");
				// for each tower element
				for(int j = 0; j < towerElements.length; j++) {
					// remove element from players inventory
					if(!player.removeElementFromInventory(Integer.parseInt(towerElements[j]))) {
						System.err.println("Error: Element of new tower is not in player's inventory. (Tower: " + i + ", element: " + j + ")");
						return false;
					} else {
						newElements++;
					}
				}
				// add tower
				Tower newTower = new Tower();
				if(!newTower.assemble(towerInstructions[i])) {
					System.err.println("Error: Tower doesn't comply with game rules. (Tower: " + i + ")");
					return false;
				}
				playerTowers.add(newTower);
			
			// if existing tower changed
			} else if(!towerInstructions[i].equals(playerTowers.get(i).getInstructions())) {
				// split tower-building instructions
				String[] towerElements = towerInstructions[i].split(",");
				// for each tower element
				for(int j = 0; j < towerElements.length; j++) {
					// if element is not already in tower
					if(!playerTowers.get(i).isElementInTower(Integer.parseInt(towerElements[j]))) {
						// remove element from players inventory
						if(!player.removeElementFromInventory(Integer.parseInt(towerElements[j]))) {
							System.err.println("Error: Element of new tower is not in player's inventory. (Tower: " + i + ", element: " + j + ")");
							return false;
						} else {
							newElements++;
						}
					}
				}
				// change tower
				if(!playerTowers.get(i).assemble(towerInstructions[i])) {
					System.err.println("Error: Tower doesn't comply with game rules. (Tower: " + i + ")");
					return false;
				}
			}
		}
		
		// Check if the player built to many new elements
		if(parameter1 + 1 < newElements) {
			System.err.println("Error: Player tried to build to many elements. (Allowed to build: " + (parameter1 + 1) + ", tried to build: " + newElements + ")");
			return false;
		}
		
		// Check if the player has enough money
		if(!player.checkMoney(parameter1 + 1)) {
			System.err.println("Error: Player doesn't have enough money.");
			return false;
		}
		
		// Subtract the cost from the player's money balance
		player.payMoney(parameter1 + 1);
		
		// Add prestige points to player's score
		player.addPoints(newElements);
		
		gameBoard.reportUpdateMoneyBuyingAgentsInventory();
		
		// It's the next player's turn
		gameBoard.nextPlayersTurn(2, newElements);
		
		return true;
	}
	
	
	/**
	 * Empties all buying agent slots.
	 */
	public void emptyBuyingAgentSlots() {
		colorConstraint = BuyingAgent.Color.NONE;
		for(int i = 0; i < buyingAgentSlots.length; i++) {
			buyingAgentSlots[i] = 0;
		}
	}
	
	
	/**
	 * Unused
	 */
	@Override
	public int[] getTowerElementSelectionIDs() throws RemoteException {
		return null;
	}

	/**
	 * Unused
	 */
	@Override
	public int[] getTowerElementPileIDs() throws RemoteException {
		return null;
	}
	
	/**
	 * Unused
	 */
	@Override
	public boolean doAction(int playerIndex, int buyingAgentID1, int buyingAgentID2) throws RemoteException {
		return false;
	}
	
	/**
	 * Unused
	 */
	@Override
	public boolean doAction(int playerIndex, int buyingAgentID1, int buyingAgentID2, int parameter1) throws RemoteException {
		return false;
	}

	/**
	 * Unused
	 */
	@Override
	public boolean doAction(int playerIndex, int buyingAgentID1, int buyingAgentID2, int parameter1, int parameter2) throws RemoteException {
		return false;
	}

}
